package go_ioc

import (
	"gitee.com/tym_hmm/go-ioc/Expr"
	"reflect"
	"strings"
	"sync"
)

var TAG_INJECT = "inject"

func NewBeanFactory() *beanFactory {
	return &beanFactory{bm: newBeanContainer(), ExprMap: make(map[string]interface{})}
}

/**
ioc工厂
*/
type beanFactory struct {
	bm      *beanContainer
	ExprMap map[string]interface{}
	l       sync.RWMutex
}

/**
设备容器添加
*/
func (this *beanFactory) Set(b ...interface{}) error {
	if b == nil || len(b) == 0 {
		return nil
	}
	this.l.Lock()
	defer this.l.Unlock()
	for _, v := range b {
		err := this.bm.add(v)
		if err != nil {
			return err
		}
	}
	return nil
}

/**
获取
*/
func (this *beanFactory) Get(v interface{}) interface{} {
	if v == nil {
		return nil
	}
	this.l.RLock()
	defer this.l.RUnlock()
	get_v := this.bm.get(v)
	if get_v.IsValid() {
		return get_v.Interface()
	}
	return nil
}

func (this *beanFactory) GetName(name string) interface{} {
	if len(strings.TrimSpace(name)) == 0 {
		return nil
	}
	this.l.RLock()
	getV := this.bm.getName(name)
	if getV.IsValid() {
		return getV.Interface()
	}
	return nil
}

func (this *beanFactory) GetBeanContainer() *beanContainer {
	return this.bm
}

func (this *beanFactory)GetBeanMap()  {

}


/**
通过表达式配置添加
*/
func (this *beanFactory) Config(cfgs ...interface{}) error {
	for _, cfg := range cfgs {
		t := reflect.TypeOf(cfg)
		if t.Kind() != reflect.Ptr {
			return IOC_ERROR_NOT_PRT //必须是指针对象
		}
		if t.Elem().Kind() != reflect.Struct {
			continue
		}
		err := this.Set(cfg) //把config本身也加入bean
		if err != nil {
			return err
		}
		this.ExprMap[t.Elem().Name()] = cfg //自动构建 ExprMap
		err = this.Apply(cfg)               //处理依赖注入 (new)
		if err != nil {
			return err
		}
		v := reflect.ValueOf(cfg)
		for i := 0; i < t.NumMethod(); i++ {
			method := v.Method(i)
			callRet := method.Call(nil)

			if callRet != nil && len(callRet) == 1 {
				err := this.Set(callRet[0].Interface())

				if err != nil {
					return err
				}
			}
		}
	}
	return nil
}

func (this *beanFactory) Apply(bean interface{}) error {
	if bean == nil {
		return IOC_ERROR_NOT_NIL
	}
	v := reflect.ValueOf(bean)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	if v.Kind() != reflect.Struct {
		return IOC_ERROR_MUSBE_STRUCT
	}
	for i := 0; i < v.NumField(); i++ {
		field := v.Type().Field(i)
		if v.Field(i).CanSet() && field.Tag.Get(TAG_INJECT) != "" {
			if field.Tag.Get("inject") != "-" { //多例模式
				ret := Expr.BeanExpr(field.Tag.Get("inject"), this.ExprMap)
				if ret != nil && !ret.IsEmpty() {
					retValue := ret[0]
					if retValue != nil {
						v.Field(i).Set(reflect.ValueOf(retValue))
						err := this.Apply(retValue)
						if err != nil {
							return err
						}
					}
				}
			} else { //单例模式
				if get_v := this.Get(field.Type); get_v != nil {
					v.Field(i).Set(reflect.ValueOf(get_v))
					err := this.Apply(get_v)
					if err != nil {
						return err
					}
				}
			}
		}
	}
	return nil
}
